package net.lulihu.common_util.exception;

import net.lulihu.ObjectKit.BeanKit;
import net.lulihu.ObjectKit.ReflectKit;
import net.lulihu.common_util.controller_result.Result;
import net.lulihu.common_util.spring.SpringHttpKit;
import lombok.extern.slf4j.Slf4j;
import net.lulihu.ObjectKit.StrKit;
import net.lulihu.common_util.validated.spring.ParamViolationExceptionUtil;
import net.lulihu.exception.ExceptionEnum;
import net.lulihu.exception.ParamResolveException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindException;
import org.springframework.validation.DefaultMessageCodesResolver;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.List;
import java.util.Objects;

/**
 * 全局的的异常拦截器（拦截所有的控制器）
 */
@Slf4j
public abstract class BusinessExceptionHandler {

    /**
     * 参数类型不匹配异常
     */
    @ExceptionHandler({MethodArgumentTypeMismatchException.class, ParamResolveException.class,
            ValidationException.class, BindException.class})
    public Object argumentTypeMismatch(Exception e) {
        if (e instanceof ConstraintViolationException) {
            List<String> messages = ParamViolationExceptionUtil.getParamViolationMessages((ConstraintViolationException) e);
            log.warn("请求参数不合法例外:{}", messages);
            return unifiedReturn(BusinessExceptionEnum.PARAM_NOT_REQUIRE, messages);
        } else if (e instanceof BindException) {
            BindException ex = (BindException) e;
            StringBuilder builder = new StringBuilder();
            for (ObjectError error : ex.getAllErrors()) {
                String[] codes = error.getCodes();
                if (codes != null)
                    builder.append(codes[0]).append(":")
                            .append(error.getDefaultMessage())
                            .append("; ");
            }
            String message = builder.toString();
            log.warn("请求参数不合法例外:{}", message);
            return unifiedReturn(BusinessExceptionEnum.PARAM_NOT_REQUIRE, message);
        }
        log.warn("参数解析例外:{}", e.getMessage());
        return unifiedReturn(BusinessExceptionEnum.PARAM_NOT_REQUIRE);
    }

    /**
     * 拦截业务异常,异常在控制范围内
     */
    @ExceptionHandler(BusinessException.class)
    public Object business(BusinessException e) {
        log.warn(StrKit.format("{}-{}", e.getCode(), e.getMessage()), e);
        return unifiedReturn(e);
    }

    /**
     * http请求 缺少必要的请求正文
     */
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public Object httpMessageNotReadable(HttpMessageNotReadableException e) {
        log.warn("缺少必要的http请求正文", e);
        return unifiedReturn(BusinessExceptionEnum.HTTP_MESSAGE_NOT_READABLE);
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(Exception.class)
    public Object unknown(Exception e) {
        log.error("运行时未知异常:", e);
        return unifiedReturn(BusinessExceptionEnum.EXPECTED_ERROR);
    }


    protected Object unifiedReturn(ExceptionEnum exceptionEnum) {
        return unifiedReturn(exceptionEnum, null);
    }

    protected Object unifiedReturn(ExceptionEnum exceptionEnum, Object data) {
        Integer httpCode = exceptionEnum.getHttpCode();
        if (null != httpCode) Objects.requireNonNull(SpringHttpKit.getResponse()).setStatus(httpCode);
        return Result.exception(exceptionEnum, data);
    }

}
